#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>


int hello_major = 500;
int hello_minor = 0;
char hello_name[1024] = "hello";

static int hello_open(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "hello_open!\n");
    return 0;
}

static int hello_release(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "hello_release!\n");
    return 0;
}

static ssize_t hello_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    ssize_t ret = 0;
    printk(KERN_INFO "hello_read!\n");
    ret = copy_to_user(buf, hello_name, count);
    if(ret < 0)
    {
        printk(KERN_ERR "hello_read failed!\n");
        return ret;
    }
    printk(KERN_INFO "hello_read: %s\n", hello_name);
    return 0;
}

static ssize_t hello_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
    ssize_t ret = 0;
    printk(KERN_INFO "hello_write!\n");
    ret =copy_from_user(hello_name, buf, count);   
    if(ret < 0)
    {
        printk(KERN_ERR "hello_write failed!\n");
        return ret;
    }
    printk(KERN_INFO "hello_write: %s\n", hello_name);
    return ret;
}

struct file_operations hello_fops = {
    .owner = THIS_MODULE,
    .open = hello_open,
    .release = hello_release,
    .read = hello_read,
    .write = hello_write,
};


struct cdev cdev = {
    .owner = THIS_MODULE,
};






int __init hello_init(void)
{
    dev_t devno =  MKDEV(hello_major, hello_minor);
    int ret = register_chrdev_region(devno, 1, "hello");
    if(ret < 0)
    {
        printk(KERN_ERR "register_chrdev_region failed!\n");
        return ret;
    }
    printk(KERN_INFO "hello_major = %d, hello_minor = %d\n", hello_major, hello_minor);  
    cdev_init(&cdev, &hello_fops);
    ret = cdev_add(&cdev, devno, 1);//向内和列表添加一个cdev结构体
    if(ret < 0)
    {
        printk(KERN_ERR "cdev_add failed!\n");
        unregister_chrdev_region(devno, 1);
        return ret;
    }
    printk(KERN_INFO "hello_init!\n");
    return 0;
}


void __exit hello_exit(void)
{
    dev_t devno =  MKDEV(hello_major, hello_minor);
    cdev_del(&cdev);
    unregister_chrdev_region(devno, 1);
    printk(KERN_INFO "cleanup_module!\n");
}



MODULE_LICENSE("GPL");
MODULE_AUTHOR("sandui");
MODULE_DESCRIPTION("A simple module");


module_init(hello_init);
module_exit(hello_exit);
